package mybatis.session;


import mybatis.exception.MyBatisException;
import mybatis.mapping.MappedStatement;
import mybatis.type.TypeHandler;

import javax.sql.DataSource;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

/**
 * 核心配置类
 *
 * @author richie696
 * @version 1.0
 * @since 2020/11/07
 */
public class Configuration {

    private final Map<String, MappedStatement> mappedStatementMap = new HashMap<>(10);
    private final Map<String, Class<?>> defaultTypeMap = new HashMap<>(10);
    private final Map<String, Class<?>> typeAliasMap = new HashMap<>(10);
    private final Map<String, TypeHandler> typeHandlerMap = new HashMap<>(10);
    private DataSource dataSource;
    private TransactionType transactionType = TransactionType.JDBC;

    public Configuration() {
        setDefaultTypeAliases();
    }

    public DataSource getDataSource() {
        return dataSource;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public Connection getConnection() {
        try {
            return dataSource.getConnection();
        } catch (SQLException throwable) {
            throw new MyBatisException(throwable);
        }
    }

    public MappedStatement getMappedStatement(String key) {
        return mappedStatementMap.get(key);
    }

    public void addMappedStatement(String key, MappedStatement value) {
        mappedStatementMap.put(key, value);
    }

    public boolean containMappedStatement(String key) {
        return mappedStatementMap.containsKey(key);
    }

    public Class<?> getTypeAlias(String key) {
        return typeAliasMap.get(key);
    }

    public void addTypeAlias(String key, Class<?> value) {
        typeAliasMap.put(key, value);
    }

    public boolean containTypeAlias(String key) {
        return typeAliasMap.containsKey(key);
    }

    public TypeHandler getTypeHandler(String key) {
        return typeHandlerMap.get(key);
    }

    public void addTypeHandler(String key, TypeHandler handler) {
        typeHandlerMap.put(key, handler);
    }

    public boolean containTypeHandler(String key) {
        return typeHandlerMap.containsKey(key);
    }

    public Class<?> getDefaultClass(String key) {
        return defaultTypeMap.get(key);
    }

    public boolean containDefaultClass(String key) {
        return defaultTypeMap.containsKey(key);
    }

    private void setDefaultTypeAliases() {
        defaultTypeMap.put(byte.class.getSimpleName().toLowerCase(), byte.class);
        defaultTypeMap.put(int.class.getSimpleName().toLowerCase(), int.class);
        defaultTypeMap.put(long.class.getSimpleName().toLowerCase(), long.class);
        defaultTypeMap.put(float.class.getSimpleName().toLowerCase(), float.class);
        defaultTypeMap.put(double.class.getSimpleName().toLowerCase(), double.class);
        defaultTypeMap.put(boolean.class.getSimpleName().toLowerCase(), boolean.class);
        defaultTypeMap.put(Byte.class.getSimpleName().toLowerCase(), Byte.class);
        defaultTypeMap.put(Integer.class.getSimpleName().toLowerCase(), Integer.class);
        defaultTypeMap.put(Long.class.getSimpleName().toLowerCase(), Long.class);
        defaultTypeMap.put(Float.class.getSimpleName().toLowerCase(), Float.class);
        defaultTypeMap.put(Double.class.getSimpleName().toLowerCase(), Double.class);
        defaultTypeMap.put(String.class.getSimpleName().toLowerCase(), String.class);
        defaultTypeMap.put(BigInteger.class.getSimpleName().toLowerCase(), BigInteger.class);
        defaultTypeMap.put(BigDecimal.class.getSimpleName().toLowerCase(), BigDecimal.class);
    }

    public TransactionType getTransactionType() {
        return transactionType;
    }

    public void setTransactionType(TransactionType transactionType) {
        this.transactionType = transactionType;
    }
}
